package com.jnevision.salary.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableMap;
import com.jnevision.attendancegroup.model.AttendanceGroup;
import com.jnevision.attendancegroup.service.AttendanceGroupServiceImpl;
import com.jnevision.clockin.model.ClockIn;
import com.jnevision.clockin.service.ClockInServiceImpl;
import com.jnevision.common.CommonQuery;
import com.jnevision.dept.model.Dept;
import com.jnevision.dept.service.DeptServiceImpl;
import com.jnevision.deptfeemultiple.model.DeptFeeMultiple;
import com.jnevision.deptfeemultiple.service.DeptFeeMultipleServiceImpl;
import com.jnevision.dict.service.DictServiceImpl;
import com.jnevision.insurancerate.mapper.InsuranceRateMapper;
import com.jnevision.insurancerate.model.InsuranceRate;
import com.jnevision.laterule.model.LateRule;
import com.jnevision.laterule.service.LateRuleServiceImpl;
import com.jnevision.leave.model.Leave;
import com.jnevision.leave.service.LeaveServiceImpl;
import com.jnevision.leaveearlyrule.model.LeaveEarlyRule;
import com.jnevision.leaveearlyrule.service.LeaveEarlyRuleServiceImpl;
import com.jnevision.leavefeeset.model.LeaveFeeSet;
import com.jnevision.leavefeeset.service.LeaveFeeSetServiceImpl;
import com.jnevision.overtime.model.Overtime;
import com.jnevision.overtime.service.OvertimeServiceImpl;
import com.jnevision.personalattendance.model.PersonalAttendance;
import com.jnevision.personalattendance.service.PersonalAttendanceServiceImpl;
import com.jnevision.salary.mapper.SalaryMapper;
import com.jnevision.salary.model.ExcelSalary;
import com.jnevision.salary.model.ExcelSalaryUn;
import com.jnevision.salary.model.Salary;
import com.jnevision.salary.model.SalaryVO;
import com.jnevision.user.service.UserServiceImpl;
import com.jnevision.userdept.model.UserDept;
import com.jnevision.userdept.service.UserDeptServiceImpl;

/**
 * <p>
 * 薪资信息 服务实现类
 * </p>
 *
 * @author gavin
 * @since 2019-07-13
 */
@Service
public class SalaryServiceImpl extends ServiceImpl<SalaryMapper, Salary> {
    @Autowired
    private InsuranceRateMapper insuranceRateMapper;
    @Autowired
    private DeptServiceImpl deptServiceImpl;
    @Autowired
    private UserDeptServiceImpl userDeptServiceImpl;
    @Autowired
    private LeaveFeeSetServiceImpl leaveFeeSetServiceImpl;
    @Autowired
    private DeptFeeMultipleServiceImpl deptFeeMultipleServiceImpl;
    @Autowired
    private LeaveServiceImpl leaveServiceImpl;
    @Autowired
    private ClockInServiceImpl clockInServiceImpl;
    @Autowired
    private PersonalAttendanceServiceImpl personalAttendanceServiceImpl;
    @Autowired
    private AttendanceGroupServiceImpl attendanceGroupServiceImpl;
    @Autowired
    private OvertimeServiceImpl overtimeServiceImpl;
    @Autowired
    private UserServiceImpl userServiceImpl;
    @Autowired
    private DictServiceImpl dictServiceImpl;
    @Autowired
    private LateRuleServiceImpl lateRuleServiceImpl;
    @Autowired
    private LeaveEarlyRuleServiceImpl leaveEarlyRuleServiceImpl;

    public IPage<Salary> depositBase(Page<Salary> page, CommonQuery query) {
        InsuranceRate rate = this.insuranceRateMapper.selectList(null).get(0); // 保险费率有且仅有一条
        IPage<Salary> retPage = this.baseMapper.depositBase(page, query);
        retPage.getRecords().forEach(wx -> {
            if (StringUtils.isNotEmpty(wx.getWxjishu())) {
                wx.setYanglao(this.multiply(wx.getWxjishu(), rate.getYanglao()));
                wx.setShiye(this.multiply(wx.getWxjishu(), rate.getShiye()));
                wx.setYiliao(this.multiply(wx.getWxjishu(), rate.getYiliao()));
            }

            wx.setGongshang(rate.getGongshang());
            wx.setShengyu(rate.getShengyu());
        });

        return retPage;
    }

    public String multiply(String... num) {
        return new BigDecimal(num[0]).multiply(new BigDecimal(num[1])).setScale(2, RoundingMode.HALF_UP).toString();
    }

    public String multiply(BigDecimal... num) {
        return num[0].multiply(num[1]).setScale(2, RoundingMode.HALF_UP).toString();
    }

    public R<List<Map<String, String>>> wageDistribution() {

        List<Dept> list = this.deptServiceImpl.list(new QueryWrapper<Dept>().eq("type", 3));
        List<Map<String, String>> result = new ArrayList<>();
        for (Dept dept : list) {
            Map<String, String> map = new HashMap<>();

            List<UserDept> list2 =
                this.userDeptServiceImpl.list(new QueryWrapper<UserDept>().eq("dept_id", dept.getId()));
            List<String> collect = list2.stream().map(UserDept::getUserId).collect(Collectors.toList());

            BigDecimal num = new BigDecimal(0);
            if (!CollectionUtils.isEmpty(collect)) {
                List<Salary> selectList = this.baseMapper.selectList(new QueryWrapper<Salary>().in("user_id", collect));

                for (int i = 0; i < selectList.size(); i++) {
                    selectList.get(i)
                        .setBaozhang(this.dictServiceImpl.getLabel("baozhang", selectList.get(i).getBaozhang()));
                    BigDecimal baozhang = new BigDecimal(selectList.get(i).getBaozhang());
                    BigDecimal gangwei = new BigDecimal(selectList.get(i).getGangwei());
                    BigDecimal gongling = new BigDecimal(selectList.get(i).getGongling());
                    BigDecimal jiabanfei = new BigDecimal(selectList.get(i).getJiabanfei());

                    num = num.add(baozhang).add(gangwei).add(gongling).add(jiabanfei);
                }

                Integer num1 = this.userServiceImpl.countLeader(dept.getId());
                Integer num2 = this.userServiceImpl.countManager(dept.getId());

                map.put("value", num.toString());
                map.put("name", dept.getName());
                map.put("leader", num1.toString());
                map.put("manager", num2.toString());
            }
            result.add(map);
        }
        return R.ok(result);
    }

    public Map<String, Object> salaryRecord(Page<SalaryVO> page, CommonQuery query, boolean insurance) {
        IPage<SalaryVO> salars = this.baseMapper.salaryRecord(page, query, insurance);

        // BigDecimal totalSalary = new BigDecimal("0");

        Map<String, Object> retMap = new HashMap<>();
        InsuranceRate rate = this.insuranceRateMapper.selectList(null).get(0); // 保险费率有且仅有一条

        for (SalaryVO sa : salars.getRecords()) {
            sa.setBaozhang(this.dictServiceImpl.getLabel("baozhang", sa.getBaozhang()));
            BigDecimal heji = new BigDecimal(sa.getGangwei()).add(new BigDecimal(sa.getGongling()))
                .add(new BigDecimal(sa.getBaozhang()));

            // 基本
            sa.setHeji(heji.toString());
            BigDecimal totalMoney = new BigDecimal("0");
            totalMoney = totalMoney.add(heji);

            // 它得
            if (StringUtils.isNotBlank(sa.getExtra())) {
                totalMoney = totalMoney.add(new BigDecimal(sa.getExtra()));
            }

            query.setUserId(sa.getUserId());
            // 加班
            BigDecimal jbf = this.calcOvertimeFee(sa.getUserId(), query.getStart(), query.getEnd());
            sa.setJiaban(jbf.toString());
            totalMoney = totalMoney.add(jbf);
            // 请假旷工的扣除计算;普通请假，婚嫁，丧假按照国家规定去除规定的三天
            BigDecimal qingjia = this.calcLeaveFee(sa.getUserId(), query.getStart(), query.getEnd());
            sa.setQingjia(qingjia.add(this.hunjia(query)).add(this.sangjia(query)).toString());
            totalMoney = totalMoney.subtract(qingjia);

            // 迟到，早退的扣除计算
            Map<String, BigDecimal> chidao = this.chidaoZaotui(query);
            sa.setChidao(chidao.get("lateMoney").toString());
            sa.setZaotui(chidao.get("earlyMoney").toString());

            totalMoney = totalMoney.subtract(chidao.get("lateMoney")).subtract(chidao.get("earlyMoney"));
            // 汇总
            // totalSalary = totalSalary.add(totalMoney);

            // 五险费用扣除
            if (sa.getInsurance()) {
                sa.setYanglao(this.multiply(sa.getWxjishu(), rate.getYanglao()));
                sa.setShiye(this.multiply(sa.getWxjishu(), rate.getShiye()));
                sa.setYiliao(this.multiply(sa.getWxjishu(), rate.getYiliao()));

                totalMoney = totalMoney.subtract(new BigDecimal(sa.getYanglao())
                    .add(new BigDecimal(sa.getShiye()).add(new BigDecimal(sa.getYiliao()))));
            }

            sa.setShifa(totalMoney.toString());
        }

        retMap.put("salarys", salars);
        // retMap.put("totalSalary", totalSalary.toString());

        return retMap;
    }

    public BigDecimal calcOvertimeFee(String userId, String start, String end) {
        /*
         * 根据用户查询部门的加班费规则，按照设定日期的倍率进行计算，判断用户的加班时间是否在设定的倍率时间内
         */
        UserDept ud = this.userDeptServiceImpl.getOne(new QueryWrapper<UserDept>().eq("user_id", userId));
        // DeptOvertimeFee deptFee =
        // this.deptOvertimeFeeServiceImpl.getOne(new QueryWrapper<DeptOvertimeFee>().eq("dept_id", ud.getDeptId()));

        // if (deptFee == null) {
        // System.err.println("部门：" + ud.getDeptId() + "》》》没有设置加班费");
        // } else {
        List<DeptFeeMultiple> feeList =
            this.deptFeeMultipleServiceImpl.list(new QueryWrapper<DeptFeeMultiple>().eq("dept_id", ud.getDeptId()));
        // 查询用户所有加班的时间段，对比加班费的时间段，对比成功按倍数计算，不在倍数范围内的按单价计算

        CommonQuery query = new CommonQuery();
        query.setUserId(userId);
        query.setStart(start);
        query.setEnd(end);

        BigDecimal feeOfHour = this.feeOfHour(ud, query);

        if (CollectionUtils.isEmpty(feeList)) {
            String duration = this.overtimeServiceImpl.overtimeDuration(query);
            if (StringUtils.isNotBlank(duration)) {
                return feeOfHour.multiply(new BigDecimal(duration));
            }
        } else {
            List<Overtime> slotList = this.overtimeServiceImpl.overtimeSlot(query);
            if (!CollectionUtils.isEmpty(slotList)) {
                BigDecimal totalOTFee = BigDecimal.valueOf(0);
                for (Overtime overtime : slotList) {
                    // 当天的加班计算方式
                    String ostart = overtime.getStart();

                    boolean flag = true;
                    for (DeptFeeMultiple dfm : feeList) {
                        if (ostart.contains(dfm.getOvertimeDate())) {
                            String dayFee = this.multiply(dfm.getMultiple(), feeOfHour.toString());
                            totalOTFee = totalOTFee.add(new BigDecimal(this.multiply(overtime.getDuration(), dayFee)));
                            flag = false;
                            break;
                        }
                    }

                    if (flag) {
                        if (StringUtils.isBlank(overtime.getDuration())) {
                            overtime.setDuration("0");
                        }
                        totalOTFee =
                            totalOTFee.add(new BigDecimal(this.multiply(overtime.getDuration(), feeOfHour.toString())));
                    }
                }

                return totalOTFee;
            }
        }
        // }

        return BigDecimal.valueOf(0);
    }

    /**
     * 根据岗位工资获取的每小时的费用
     * 
     * @param ud
     * @param query
     * @return
     */
    public BigDecimal feeOfHour(UserDept ud, CommonQuery query) {
        AttendanceGroup ag = this.attendanceGroupServiceImpl.getOne(new QueryWrapper<AttendanceGroup>()
            .eq("dept_id", ud.getDeptId()).eq("attendance_cycle", query.getStart().substring(0, 7)));
        if (ag == null) {
            System.err.println(ud.getUserId() + ">>>用户没有对应的考勤组计划，无法计算请假需要扣除的费用");
            return BigDecimal.valueOf(0);
        }

        Salary sa = this.getOne(new QueryWrapper<Salary>().eq("user_id", ud.getUserId()));
        // sa.setBaozhang(this.dictServiceImpl.getLabel("baozhang", sa.getBaozhang()));

        // BigDecimal jiben = new BigDecimal(sa.getBaozhang()).add(new BigDecimal(sa.getGangwei()));
        BigDecimal gangwei = new BigDecimal(sa.getGangwei());

        BigDecimal hourOfDay = this.workHourOfDay(ud, query);// new BigDecimal(monMin + afterMin).divide(new
                                                             // BigDecimal(3600), RoundingMode.HALF_UP);

        PersonalAttendance pa = this.personalAttendanceServiceImpl
            .getOne(new QueryWrapper<PersonalAttendance>().eq("group_id", ag.getId()).eq("user_id", ud.getUserId()));
        if (pa == null) {
            System.out.println(ud.getUserId() + "用户没有对应考勤计划，无法计算请假需要扣除的费用");
            return BigDecimal.valueOf(0);
        }

        int workday = 0; // 工作日，休息日对应的天数

        for (String day : pa.getDays()) {
            if (StringUtils.equals(day, "√")) {
                workday++;
            }
        }

        return gangwei.divide(hourOfDay.multiply(new BigDecimal(workday)), RoundingMode.HALF_UP);
    }

    /**
     * 每天的工作时长
     * 
     * @param ud
     * @param query
     * @return
     */
    public BigDecimal workHourOfDay(UserDept ud, CommonQuery query) {
        AttendanceGroup ag = this.attendanceGroupServiceImpl.getOne(new QueryWrapper<AttendanceGroup>()
            .eq("dept_id", ud.getDeptId()).eq("attendance_cycle", query.getStart().substring(0, 7)));
        if (ag == null) {
            System.err.println(ud.getUserId() + ">>>用户没有对应的考勤计划，无法计算请假需要扣除的费用");
            return BigDecimal.valueOf(0);
        }

        int monMin = LocalTime.parse(ag.getMorningEnd() + ":00").toSecondOfDay()
            - LocalTime.parse(ag.getMorningStart() + ":00").toSecondOfDay();
        int afterMin = LocalTime.parse(ag.getAfternoonEnd() + ":00").toSecondOfDay()
            - LocalTime.parse(ag.getAfternoonStart() + ":00").toSecondOfDay();
        BigDecimal hourOfDay = new BigDecimal(monMin + afterMin).divide(new BigDecimal(3600), RoundingMode.HALF_UP);

        return hourOfDay;
    }

    public BigDecimal calcLeaveFee(String userId, String start, String end) {
        /**
         * 根据用户获取所在的部门或者项目部 根据项目部制定的请假扣款规则，决定是按天扣款，还是按照小时扣款； 把请假类型是调休的排除后再扣款
         */
        CommonQuery query = new CommonQuery();
        query.setUserId(userId);
        query.setStart(start);
        query.setEnd(end);

        // 应该返回请假时间段，根据每次的请假时长来计算rule是0的时候
        UserDept ud = this.userDeptServiceImpl.getOne(new QueryWrapper<UserDept>().eq("user_id", userId));
        LeaveFeeSet leavefee =
            this.leaveFeeSetServiceImpl.getOne(new QueryWrapper<LeaveFeeSet>().eq("dept_id", ud.getDeptId()));
        if (leavefee != null) {
            // AttendanceGroup ag = this.attendanceGroupServiceImpl.getOne(new QueryWrapper<AttendanceGroup>()
            // .eq("dept_id", ud.getDeptId()).eq("attendance_cycle", start.substring(0, 7)));
            // if (ag == null) {
            // System.err.println(userId + ">>>用户没有对应的考勤计划，无法计算请假需要扣除的费用");
            // return BigDecimal.valueOf(0);
            // }
            //
            // PersonalAttendance pa = this.personalAttendanceServiceImpl
            // .getOne(new QueryWrapper<PersonalAttendance>().eq("group_id", ag.getId()).eq("user_id", userId));
            // int workday = 0; // 工作日，休息日对应的天数
            // for (String day : pa.getDays()) {
            // if (StringUtils.equals(day, "√")) {
            // workday++;
            // }
            // }
            // Salary sa = this.getOne(new QueryWrapper<Salary>().eq("user_id", userId));
            // // sa.setBaozhang(this.dictServiceImpl.getLabel("baozhang", sa.getBaozhang()));
            //
            // // BigDecimal jiben = new BigDecimal(sa.getBaozhang()).add(new BigDecimal(sa.getGangwei()));
            // BigDecimal gangwei = new BigDecimal(sa.getGangwei());
            //
            // int kuanggongDay = Optional
            // .ofNullable(this.clockInServiceImpl.list(new QueryWrapper<ClockIn>().eq("user_id", userId)
            // .ge("work_day", start).lt("work_day", end).eq("clock_in_status", 5)))
            // .orElseGet(ArrayList::new).size(); // 旷工天数
            //

            int kuanggongDay = Optional
                .ofNullable(this.clockInServiceImpl.list(new QueryWrapper<ClockIn>().eq("user_id", ud.getUserId())
                    .ge("work_day", query.getStart()).lt("work_day", query.getEnd()).eq("clock_in_status", 5)))
                .orElseGet(ArrayList::new).size(); // 旷工天数
            BigDecimal workHourOfDay = this.workHourOfDay(ud, query);

            // // 获取用户的应出勤日，计算出每天的工作时长；最后用公式计算出请假应扣钱数，基本工资（保障+岗位）
            //
            // int monMin = LocalTime.parse(ag.getMorningEnd() + ":00").toSecondOfDay()
            // - LocalTime.parse(ag.getMorningStart() + ":00").toSecondOfDay();
            // int afterMin = LocalTime.parse(ag.getAfternoonEnd() + ":00").toSecondOfDay()
            // - LocalTime.parse(ag.getAfternoonStart() + ":00").toSecondOfDay();
            // BigDecimal hourOfDay = new BigDecimal(monMin + afterMin + kuanggongDay * 3600).divide(new
            // BigDecimal(3600),
            // RoundingMode.HALF_UP);
            BigDecimal feeOfHour = this.feeOfHour(ud, query);
            // TODO 婚假丧假三天不扣款，迟到早退扣款
            if (leavefee.getRule() == 0) {
                String nonMoney = leavefee.getNonDeductionTime();

                // TODO 根据时间段判断在哪个时间段，然后再扣费
                List<Leave> leaveList = this.leaveServiceImpl.list(
                    new QueryWrapper<Leave>().eq("user_id", userId).between("start", query.getStart(), query.getEnd()));
                if (!CollectionUtils.isEmpty(leaveList)) {
                    // BigDecimal pricePerDay = gangwei.divide(new BigDecimal(workday), RoundingMode.HALF_UP);
                    BigDecimal leaveDay = BigDecimal.valueOf(0);

                    for (Leave leave : leaveList) {
                        Float duration = Float.parseFloat(leave.getDuration());
                        Float mian = Float.parseFloat(nonMoney);
                        if (duration <= mian) {
                            // 小于y小时规定时间不扣钱
                        } else if (duration > mian) {
                            // 大于y小时规定时间按小时计算费用
                            leaveDay =
                                leaveDay.add(new BigDecimal(leave.getDuration())).subtract(new BigDecimal(nonMoney));
                        }
                    }

                    BigDecimal totalLeave = workHourOfDay.multiply(BigDecimal.valueOf(kuanggongDay)).add(leaveDay)
                        .add(this.hunjia(query)).add(this.sangjia(query));
                    return feeOfHour.multiply(totalLeave).setScale(2, RoundingMode.HALF_UP);
                }
            } else {
                String duration = this.leaveServiceImpl.myLeaveDuration(query); // 总请假时长
                BigDecimal totalLeave = workHourOfDay.multiply(BigDecimal.valueOf(kuanggongDay)).add(this.hunjia(query))
                    .add(this.sangjia(query));

                if (StringUtils.isNotBlank(duration)) {
                    totalLeave = totalLeave.add(new BigDecimal(duration));
                }

                return feeOfHour.multiply(totalLeave).setScale(2, RoundingMode.HALF_UP);
            }
        } else {
            System.err.println("部门：" + ud.getDeptId() + "》》》没有设置请假扣费");
        }

        return BigDecimal.valueOf(0);
    }

    /**
     * 婚假，返回需要扣除费用的时间；法定假期三天不扣钱
     * 
     * @param query
     * @return
     */
    public BigDecimal hunjia(CommonQuery query) {
        String hunjia = this.leaveServiceImpl.hunjia(query);
        if (StringUtils.isNotBlank(hunjia)) {
            if (Float.parseFloat(hunjia) <= 3) {
                return BigDecimal.valueOf(0);
            } else {
                return new BigDecimal(hunjia).subtract(BigDecimal.valueOf(3));
            }
        }
        return BigDecimal.valueOf(0);
    }

    /**
     * 丧假，返回需要扣除费用的时间；法定假期三天不扣钱
     * 
     * @param query
     * @return
     */
    public BigDecimal sangjia(CommonQuery query) {
        String sangjia = this.leaveServiceImpl.sangjia(query);
        if (StringUtils.isNotBlank(sangjia)) {
            if (Float.parseFloat(sangjia) <= 3) {
                return BigDecimal.valueOf(0);
            } else {
                return new BigDecimal(sangjia).subtract(BigDecimal.valueOf(3));
            }
        }
        return BigDecimal.valueOf(0);
    }

    /**
     * 去除人性化后需要扣除的费用
     * 
     * @param query
     * @return
     */
    public Map<String, BigDecimal> chidaoZaotui(CommonQuery query) {
        UserDept ud = this.userDeptServiceImpl.getOne(new QueryWrapper<UserDept>().eq("user_id", query.getUserId()));
        AttendanceGroup ag = this.attendanceGroupServiceImpl.getOne(new QueryWrapper<AttendanceGroup>()
            .eq("dept_id", ud.getDeptId()).eq("attendance_cycle", query.getStart().substring(0, 7)));
        BigDecimal lateMoney = new BigDecimal(0);
        BigDecimal earlyMoney = new BigDecimal(0);
        // TODO 保安排班计划
        if (ag == null || ag.getName().contains("保安")) {
            System.err.println(ud.getUserId() + ">>>用户没有对应的考勤计划，无法计算请假需要扣除的费用");
            return ImmutableMap.of("lateMoney", lateMoney, "earlyMoney", earlyMoney);
        }

        Map<String, BigDecimal> retMap = new HashMap<>();

        LateRule late = this.lateRuleServiceImpl.getOne(new QueryWrapper<LateRule>().eq("group_id", ag.getId()));
        LeaveEarlyRule early =
            this.leaveEarlyRuleServiceImpl.getOne(new QueryWrapper<LeaveEarlyRule>().eq("group_id", ag.getId()));

        List<ClockIn> clockList = this.clockInServiceImpl.list(new QueryWrapper<ClockIn>()
            .ge("work_day", query.getStart()).lt("work_day", query.getEnd()).eq("user_id", query.getUserId()));

        for (ClockIn clockIn : clockList) {
            // 迟到0按次，1按时长
            if (late.getModel().equals("1")) {
                int late1 = 0, late2 = 0;
                if (StringUtils.isNotBlank(clockIn.getWorkShift())) {
                    if ((late1 = (LocalTime.parse(ag.getMorningStart()).toSecondOfDay()
                        - LocalTime.parse(clockIn.getWorkShift().substring(11)).toSecondOfDay()) / 60) < 0) {
                        if (Integer.parseInt(late.getExempt()) - late1 < 0) { // 任性化时间内不扣钱
                            lateMoney = lateMoney.add(new BigDecimal(late1 - Integer.parseInt(late.getExempt()))
                                .multiply(new BigDecimal(late.getMoney())));
                        }
                    }
                }

                // if ((late2 = (LocalTime.parse(ag.getAfternoonStart()).toSecondOfDay()
                // - LocalTime.parse(clockIn.getWorkShift1().substring(11)).toSecondOfDay()) / 60) < 0) {
                // if (Integer.parseInt(late.getExempt()) - late2 < 0) { // 任性化时间内不扣钱
                // lateMoney = lateMoney.add(new BigDecimal(late2 - Integer.parseInt(late.getExempt()))
                // .multiply(new BigDecimal(late.getMoney())));
                // }
                // }
            } else if (late.getModel().equals("0")) {
                // TODO 暂时不做
                System.err.println("迟到暂时没有按次的计算方式，请稍后...");
            }

            // 早退0按次，1按时长
            if (early.getModel().equals("1")) {
                int early1 = 0, early2 = 0;
                // if ((early1 = (LocalTime.parse(ag.getMorningEnd()).toSecondOfDay()
                // - LocalTime.parse(clockIn.getClosingTime1().substring(11)).toSecondOfDay()) / 60) > 0) {
                // if (Integer.parseInt(early.getExempt()) - early1 < 0) { // 任性化时间内不扣钱
                // earlyMoney = earlyMoney.add(new BigDecimal(early1 - Integer.parseInt(early.getExempt()))
                // .multiply(new BigDecimal(early.getMoney())));
                // }
                // }

                if (StringUtils.isNotBlank(clockIn.getClosingTime())) {
                    if ((early2 = (LocalTime.parse(ag.getAfternoonEnd()).toSecondOfDay()
                        - LocalTime.parse(clockIn.getClosingTime().substring(11)).toSecondOfDay()) / 60) > 0) {
                        if (Integer.parseInt(early.getExempt()) - early2 < 0) { // 任性化时间内不扣钱
                            earlyMoney = earlyMoney.add(new BigDecimal(early2 - Integer.parseInt(early.getExempt()))
                                .multiply(new BigDecimal(early.getMoney())));
                        }
                    }
                }
            } else if (early.getModel().equals("0")) {
                System.err.println("早退暂时没有按次的计算方式，请稍后...");
                // TODO 暂时不做
            }
        }

        retMap.put("lateMoney", lateMoney);
        retMap.put("earlyMoney", earlyMoney);
        return retMap;
    }

    /**
     * 工资明细导出
     * 
     * @param response
     * @param query
     * @param insurance
     */
    public void exportSalary(HttpServletResponse response, CommonQuery query, boolean insurance) {

        List<SalaryVO> salars = this.baseMapper.salaryRecord(query, insurance);

        BigDecimal totalSalary = new BigDecimal("0");
        List<ExcelSalary> list = null;
        List<ExcelSalaryUn> listun = null;
        if (insurance) {
            list = new ArrayList<>();
        } else {
            listun = new ArrayList<>();
        }
        try {
            for (SalaryVO sa : salars) {
                sa.setBaozhang(this.dictServiceImpl.getLabel("baozhang", sa.getBaozhang()));
                BigDecimal heji = new BigDecimal(sa.getGangwei()).add(new BigDecimal(sa.getGongling()))
                    .add(new BigDecimal(sa.getBaozhang()));

                sa.setHeji(heji.toString());
                BigDecimal totalMoney = new BigDecimal("0");
                totalMoney = totalMoney.add(heji);

                if (StringUtils.isNotBlank(sa.getExtra())) {
                    totalMoney = totalMoney.add(new BigDecimal(sa.getExtra()));
                }

                query.setUserId(sa.getUserId());
                // 加班费
                BigDecimal jbf = this.calcOvertimeFee(sa.getUserId(), query.getStart(), query.getEnd());
                sa.setJiaban(jbf.toString());
                totalMoney = totalMoney.add(jbf);
                // 请假旷工的扣除计算
                BigDecimal qingjia = this.calcLeaveFee(sa.getUserId(), query.getStart(), query.getEnd());
                sa.setQingjia(qingjia.toString());
                totalMoney = totalMoney.subtract(qingjia);

                // 汇总
                totalSalary = totalSalary.add(totalMoney);

                if (sa.getInsurance()) {
                    InsuranceRate rate = this.insuranceRateMapper.selectList(null).get(0); // 保险费率有且仅有一条
                    sa.setYanglao(this.multiply(sa.getWxjishu(), rate.getYanglao()));
                    sa.setShiye(this.multiply(sa.getWxjishu(), rate.getShiye()));
                    sa.setYiliao(this.multiply(sa.getWxjishu(), rate.getYiliao()));

                    totalMoney = totalMoney.subtract(new BigDecimal(sa.getYanglao())
                        .add(new BigDecimal(sa.getShiye()).add(new BigDecimal(sa.getYiliao()))));

                }
                sa.setShifa(totalMoney.toString());

                ExcelSalary es = null;
                ExcelSalaryUn esUn = null;
                if (insurance) {
                    es = new ExcelSalary();
                    BeanUtils.copyProperties(sa, es);
                    list.add(es);
                } else {
                    esUn = new ExcelSalaryUn();
                    BeanUtils.copyProperties(sa, esUn);
                    listun.add(esUn);
                }

            }

            ExcelSalary total = null;
            ExcelSalaryUn totalUn = null;
            if (insurance) {
                total = new ExcelSalary();
                total.setUserName("薪资共计：");
                total.setDeptName(totalSalary.toString());
                list.add(total);
            } else {
                totalUn = new ExcelSalaryUn();
                totalUn.setUserName("薪资共计：");
                totalUn.setDeptName(totalSalary.toString());
                listun.add(totalUn);
            }

            String fileName = new String("工资明细".getBytes(), "iso-8859-1");
            ServletOutputStream out = response.getOutputStream();
            ExcelWriter writer = EasyExcelFactory.getWriter(out);
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename= " + fileName + ".xlsx");
            Sheet sheet = new Sheet(1, 1, insurance ? ExcelSalary.class : ExcelSalaryUn.class);
            writer.write(insurance ? list : listun, sheet);
            writer.finish();
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
